#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#include <sys/epoll.h>

#define BUFFER_SIZE 512
#define MAX_FDS    5

// ./chat <port>
int main(int argc, char const *argv[])
{
    if(argc != 2) return -1;
    struct sockaddr_in server = {
        .sin_family = AF_INET,
        .sin_port = htons(atoi(argv[1])),
        .sin_addr.s_addr = INADDR_ANY
    };
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(bind(sockfd, (struct sockaddr *)&server, sizeof(server)) != 0){
        perror("bind");
        return -1;
    }
    listen(sockfd, 1);

    int epollfd = epoll_create1(0);  // 创建epoll实例
    if(epollfd < 0) {
        perror("epoll");
        close(sockfd);
        return -1;
    }

    // 将sockfd添加到epoll中
    struct epoll_event ev, events[MAX_FDS];

    ev.data.fd = sockfd;
    ev.events = EPOLLIN ;
    
    epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &ev);  // 成功返回0，失败-1

    // 将标准输入 添加到 epoll中
    ev.data.fd = STDIN_FILENO;
    ev.events = EPOLLIN;
    epoll_ctl(epollfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev);

    // 定义已连接的clientfd
    int clientfd = -1;  // -1 表示未连接
    
    printf("------Chat(%s) Running------\n", argv[1]);

    // 开始等待EPOLL中的FD就绪并处理
    int nfds = 0;
    int i;
    char buf[BUFFER_SIZE] = "";
    char client_ip[16] = ""; // 已连接客户端IP
    while(1){
        // 等待有FD就绪
        nfds = epoll_wait(epollfd, events, MAX_FDS, -1);
        if(nfds <= 0){
            break;
        }
        for(i=0;i<nfds; i++){
            if(events[i].data.fd == STDIN_FILENO){
                // 读取键盘输入的数据
                bzero(buf, BUFFER_SIZE); // 清空缓冲区
                fgets(buf, BUFFER_SIZE, stdin);
                buf[strlen(buf)-1] = 0;

                if(strncmp(buf, "exit", 4) == 0){
                    goto __exit__;
                }

                // 向客户端发送消息
                if(clientfd != -1){
                    send(clientfd, buf, strlen(buf), 0);
                }
            }
            
            if(events[i].data.fd == sockfd){  // 客户端连接
                // 接收客户端连接
                struct sockaddr_in client;
                socklen_t client_len = sizeof(client);
                clientfd = accept(sockfd,(struct sockaddr *)&client, &client_len);
                if(clientfd <= 0){
                    clientfd = -1;
                    continue;
                }
                // 从client中读取IP地址
                bzero(client_ip, 16);
                inet_ntop(AF_INET, &client.sin_addr.s_addr, client_ip, 16);

                //显示连接信息
                printf("%s 客户端已连接\n", client_ip);

                // 将客户端FD添加 到EPOLL中
                ev.data.fd = clientfd;
                ev.events = EPOLLIN;
                epoll_ctl(epollfd, EPOLL_CTL_ADD, clientfd, &ev);

                // 将sockfd 从EPOLL删除了 （只接一个客户端）
                epoll_ctl(epollfd, EPOLL_CTL_DEL, sockfd, NULL);
            }
       
            if(clientfd !=-1 && events[i].data.fd == clientfd){
                bzero(buf, BUFFER_SIZE);
                ssize_t len = recv(clientfd, buf, BUFFER_SIZE, 0);
                if(len <= 0){
                    // 客户端断开
                    printf("%s 客户端已断开\n", client_ip);
                    close(clientfd);

                    // 将clientfd从epoll中删除
                    epoll_ctl(epollfd, EPOLL_CTL_DEL, clientfd, NULL);
                    clientfd = -1;

                    // 将sockfd添加到epoll中，接收新的客户端
                    ev.data.fd = sockfd;
                    ev.events = EPOLLIN;
                    epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &ev);
                }else{
                    printf("%s: %s\n",client_ip, buf);
                }
                
            }
        }
    }

__exit__:
    close(sockfd);
    close(epollfd);
    printf("---exit--\n");
    return 0;
}

